package com.plian.system.service.pf.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.plian.Tools.*;
import com.plian.Tools.pagedata.PageData;
import com.plian.system.constant.sys.FormStatusConstant;
import com.plian.system.dto.pf.BaseExpenditureImplementationDTO;
import com.plian.system.entity.fr.indicators.FinanceIndicators;
import com.plian.system.entity.fr.indicators.IndicatorsValue;
import com.plian.system.entity.pf.AppraisalIndex;
import com.plian.system.entity.pf.BaseExpenditureImplementation;
import com.plian.system.entity.sys.Org;
import com.plian.system.mapper.fr.indicators.FinanceIndicatorsMapper;
import com.plian.system.mapper.fr.indicators.IndicatorsValueMapper;
import com.plian.system.mapper.pf.BaseExpenditureImplementationMapper;
import com.plian.system.model.CommonCode;
import com.plian.system.model.ListResult;
import com.plian.system.model.ObjResult;
import com.plian.system.model.R;
import com.plian.system.config.exception.MyRuntimeException;
import com.plian.system.mybatis.base.BaseServiceImpl;
import com.plian.system.mybatis.search.SearchEntity;
import com.plian.system.mybatis.search.SearchParamEntiy;
import com.plian.system.mybatis.search.TokenSearch;
import com.plian.system.mybatis.support.Condition;
import com.plian.system.mybatis.support.Query;
import com.plian.system.node.ForestNodeMerger;
import com.plian.system.properties.GzwProperties;
import com.plian.system.service.pf.IAppraisalIndexService;
import com.plian.system.service.pf.IBaseExpenditureImplementationService;
import com.plian.system.service.sys.code.IFormCodeService;
import com.plian.system.service.sys.orgzation.IOrgService;
import com.plian.system.service.wf.FormWorkflowService;
import com.plian.system.vo.pf.BaseExpenditureImplementationVO;
import com.plian.system.vo.pf.ExpenditureOrgVO;
import com.plian.system.vo.report.HeaderVO;
import com.plian.system.vo.report.ReportReturnVO;
import com.plian.system.vo.report.ReportVO;
import com.plian.system.vo.sys.OrgVO;
import com.plian.system.wrapper.pf.BaseExpenditureImplementationWrapper;
import com.plian.system.wrapper.sys.OrgWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static com.plian.system.constant.sys.FormStatusConstant.UNREVIEWED;
import static com.plian.system.constant.sys.FormTypeConstant.PF_EXPENDITURE_IMPLEMENTATION;

/**
 * @Description: TODO
 * @Author: Take-off
 * @Date: 2023/3/13 3:12 PM
 * @Param
 * @return
 * @Version: 1.0
 **/
@Slf4j
@Service
@AllArgsConstructor
public class BaseExpenditureImplementationServiceImpl extends BaseServiceImpl<BaseExpenditureImplementationMapper, BaseExpenditureImplementation> implements IBaseExpenditureImplementationService {
    private FormWorkflowService formWorkflowService;

    private IFormCodeService formCodeService;

    private BaseExpenditureImplementationWrapper implementationWrapper;

    private IAppraisalIndexService appraisalIndexService;

    private IndicatorsValueMapper indicatorsValueMapper;

    private FinanceIndicatorsMapper indicatorsMapper;

    private GzwProperties gzwProperties;

    private IOrgService orgService;

    private OrgWrapper orgWrapper;

    @Override
    public boolean saveOrUpdate(BaseExpenditureImplementation expenditureImplementation) {
        if (!Optional.ofNullable(expenditureImplementation.getStatus()).isPresent()) {
            expenditureImplementation.setStatus(FormStatusConstant.UNREVIEWED);
        }
        if (expenditureImplementation.getStatus().equals(FormStatusConstant.REJECT)) {
            expenditureImplementation.setStatus(FormStatusConstant.UNREVIEWED);
        }
        if (!Optional.ofNullable(expenditureImplementation.getId()).isPresent()) {
            expenditureImplementation.setCode(formCodeService.getCode(PF_EXPENDITURE_IMPLEMENTATION));
            expenditureImplementation.setFormType(String.valueOf(PF_EXPENDITURE_IMPLEMENTATION));
        }

        return super.saveOrUpdate(expenditureImplementation);
    }

    @Override
    @Transactional(rollbackFor=RuntimeException.class)
    public boolean deleteLogic(List<Long> ids) {
        for (Long id : ids) {
            BaseExpenditureImplementation expenditureImplementation = getById(id);
            if (expenditureImplementation == null) {
                return false;
            } else if (expenditureImplementation.getStatus() != null &&
                    (expenditureImplementation.getStatus() != FormStatusConstant.STASH && expenditureImplementation.getStatus() != FormStatusConstant.UNREVIEWED)) {
                return false;
            }
            formWorkflowService.deleteProcessInstance(String.valueOf(id));
        }

        boolean result = super.deleteLogic(ids);
        return result;
    }

    @Override
    public HashMap<String,Object> commit(String id) {
        handleStatus(Long.valueOf(id), FormStatusConstant.FLOW);

        //将需要提交的流程变量返回，用于工作流侧
        return new HashMap<String,Object>();
    }

    @Override
    public Boolean finish(String id) {
        return handleStatus(Long.valueOf(id), FormStatusConstant.FINISH);
    }

    @Override
    public Boolean reject(String id, int formState,String comment) {
        return handleStatus(Long.valueOf(id), formState);
    }

    @Override
    public Boolean cancel(Long id) {
        return handleStatus(Long.valueOf(id), FormStatusConstant.UNREVIEWED);
    }

    @Override
    public List<PageData> findByIds(List<String> formIds) {
        LambdaQueryWrapper<BaseExpenditureImplementation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(BaseExpenditureImplementation::getId, Func.toLongList(StringUtils.join(formIds, StringPool.COMMA)));
        List<BaseExpenditureImplementation> expenditureImplementations = list(queryWrapper);
        List<BaseExpenditureImplementationVO> expenditureImplementationVOS = implementationWrapper.entityToVO(expenditureImplementations);
        List<PageData> pageDataList = new ArrayList<>();
        try{
            if (CollectionUtil.isNotEmpty(expenditureImplementationVOS)){
                for (BaseExpenditureImplementationVO vo : expenditureImplementationVOS){
                    PageData pd = new PageData();
                    pd.put("id", vo.getId());
                    pd.put("UNITNAME", vo.getFillingUnitName());
                    pd.put("APPLICANTNAME", vo.getCreateUserName());
                    pd.put("applicantId", vo.getCreateUser());
                    pd.put("applyOrganizationId", vo.getFillingUnitId());
                    pd.put("formType", vo.getFormType());
                    pd.put("orgName", vo.getFillingUnitName());
                    pageDataList.add(pd);
                }
            }

            return pageDataList;
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
        }
        return pageDataList;
    }

    @Override
    public void goBackToStash(String formId) {
        handleStatus(Long.valueOf(formId), UNREVIEWED);
    }

    /**
     * 统一处理状态机事件方法
     *
     * @param id          主键
     * @param updateStatus  更新状态
     * @return boolean
     */
    private Boolean handleStatus(Long id, int updateStatus) {
        try {
            BaseExpenditureImplementation expenditureImplementation = getById(id);
            /**
             * 设置审批人和审批时间
             */
            if (updateStatus == FormStatusConstant.FINISH){
                expenditureImplementation.setApprovedUser(TokenUtil.getTokenUserId());
                Date now = DateUtil.now();
                expenditureImplementation.setApprovedTime(now);
            }
            expenditureImplementation.setStatus(updateStatus);
            updateById(expenditureImplementation);
            return true;
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor=RuntimeException.class)
    public boolean submit(BaseExpenditureImplementation expenditureImplementation) {
        boolean result = saveOrUpdate(expenditureImplementation);

        return result;
    }

    @Override
    public R<BaseExpenditureImplementationVO> getDetailObj(BaseExpenditureImplementation expenditureImplementation) {
        BaseExpenditureImplementation detail = getOne(Condition.getQueryWrapper(expenditureImplementation));
        BaseExpenditureImplementationVO expenditureImplementationVO = implementationWrapper.entityToVO(detail);
        if (Optional.ofNullable(expenditureImplementationVO).isPresent()){
            // 预算表取值
            getBudge(expenditureImplementationVO);
        }
        return R.data(expenditureImplementationVO);
    }

    @Override
    public R<BaseExpenditureImplementationVO> getLastDetailObj(BaseExpenditureImplementationDTO dto){
        BaseExpenditureImplementationVO expenditureImplementationVO = new BaseExpenditureImplementationVO();
        String executionMonth = dto.getExecutionMonth();
        if (StringUtil.isNotBlank(executionMonth)){
            List<BaseExpenditureImplementation> lastImplementations = list(new LambdaQueryWrapper<BaseExpenditureImplementation>().eq(BaseExpenditureImplementation::getFillingUnitId, dto.getFillingUnitId())
                    .like(BaseExpenditureImplementation::getExecutionMonth, executionMonth.split("-")[0])
                    .lt(BaseExpenditureImplementation::getExecutionMonth,executionMonth));
            if (CollectionUtil.isNotEmpty(lastImplementations)){
                Optional<BaseExpenditureImplementation> first = lastImplementations.stream().sorted(Comparator.comparing(BaseExpenditureImplementation::getExecutionMonth).reversed()).findFirst();
                if (first.isPresent()){
                    BaseExpenditureImplementation baseExpenditureImplementation = first.get();
                    expenditureImplementationVO = implementationWrapper.entityToVO(baseExpenditureImplementation);
                    getBudge(expenditureImplementationVO);
                }
            }

        }

        return R.data(expenditureImplementationVO);
    }

    /**
     * @Description: //TODO 获取预算表数据
     * @Author: Take-off
     * @Date: 4:53 PM 2023/3/13
     * @Param: [implementationVO]
     * @return: void
     **/
    public void getBudge(BaseExpenditureImplementationVO implementationVO){
        String executionMonth = implementationVO.getExecutionMonth();
        if (Optional.ofNullable(executionMonth).isPresent()){
            String year = executionMonth.split("-")[0];
            String month = executionMonth.split("-")[1];
            //获取预算指标
            List<AppraisalIndex> indexList = appraisalIndexService.listByTableCodeAndYear("005",year);
            List<String> codeLists = indexList.stream().map(AppraisalIndex::getCompleteCode).filter(m -> Optional.ofNullable(m).isPresent()).collect(Collectors.toList());
            List<FinanceIndicators> indicators = indicatorsMapper.selectList(new LambdaQueryWrapper<FinanceIndicators>().in(FinanceIndicators::getCode, codeLists));
            if (CollectionUtil.isNotEmpty(indicators)){
                List<IndicatorsValue> indicatorsValues = indicatorsValueMapper.selectList(new LambdaQueryWrapper<IndicatorsValue>().eq(IndicatorsValue::getOrgId, implementationVO.getFillingUnitId())
                        .eq(IndicatorsValue::getFyear, year).eq(IndicatorsValue::getFmonth, "00")
                        .in(IndicatorsValue::getIndicatorsId, indicators.stream().map(FinanceIndicators::getId).collect(Collectors.toList())));
                getValue(indicatorsValues,indicators,implementationVO);
            }
        }
    }

    /**
     * @Description: //TODO 塞入预算数据
     * @Author: Take-off
     * @Date: 9:36 AM 2023/3/14
     * @Param: [indicatorsValues, indicators, implementationVO]
     * @return: void
     **/
    private void  getValue(List<IndicatorsValue> indicatorsValues,List<FinanceIndicators> indicators,BaseExpenditureImplementationVO implementationVO){
        if (CollectionUtil.isNotEmpty(indicatorsValues)){
            BigDecimal sumValue = BigDecimal.ZERO;
            for (FinanceIndicators indicator :indicators){
                List<IndicatorsValue> values = indicatorsValues.stream().filter(value -> indicator.getId().equals(value.getIndicatorsId())).collect(Collectors.toList());
                BigDecimal fvalue = BigDecimal.ZERO;
                if (CollectionUtil.isNotEmpty(values)){
                    //取合并表
                    List<IndicatorsValue> valueList = values.stream().filter(m -> "1".equals(m.getIsGroup())).collect(Collectors.toList());
                    if (CollectionUtil.isNotEmpty(valueList)){
                        fvalue = valueList.get(0).getFvalue();
                    }else {
                        //取单户表
                        valueList = values.stream().filter(m -> "0".equals(m.getIsGroup())).collect(Collectors.toList());
                        if (CollectionUtil.isNotEmpty(valueList)){
                            fvalue = valueList.get(0).getFvalue();
                        }
                    }
                }
                switch (indicator.getCode()){
                    case "Y81":implementationVO.setVehicleBudge(fvalue);sumValue= sumValue.add(fvalue);break;
                    case "Y82":implementationVO.setCommunicationBudge(fvalue);sumValue= sumValue.add(fvalue);break;
                    case "Y83":implementationVO.setEntertainBudge(fvalue);sumValue= sumValue.add(fvalue);break;
                    case "Y84":implementationVO.setOutsideBudge(fvalue);sumValue= sumValue.add(fvalue);break;
                    case "Y85":implementationVO.setTripBudge(fvalue);sumValue= sumValue.add(fvalue);break;
                    default:break;
                }
            }
            implementationVO.setTotalBudge(sumValue);
        }
    }

    @Override
    public ListResult<BaseExpenditureImplementationVO> list(@RequestBody Query query) {
        List<SearchEntity> entityList = query.getSearch();
        if (query.getAscs()==null&&query.getDescs()==null){
            query.setDescs("create_time");
        }
        QueryWrapper<BaseExpenditureImplementation> queryWrapper = SearchParamEntiy.getQueryWrapper(
                Condition.getQueryWrapper(new BaseExpenditureImplementation()), entityList
        );

        TokenSearch<BaseExpenditureImplementation> tokenSearch = new TokenSearch<>();
		tokenSearch.addTokenQuery(queryWrapper, query);

        IPage<BaseExpenditureImplementation> pages = page(Condition.getPage(query), queryWrapper);
        List<BaseExpenditureImplementationVO> expenditureImplementationVOS = implementationWrapper.entityToVO(pages.getRecords());
        ListResult<BaseExpenditureImplementationVO> listResult = new ListResult<>(CommonCode.SUCCESS);
        listResult.setList(expenditureImplementationVOS);
        listResult.setTotal(Long.valueOf(pages.getTotal()).intValue());
        return listResult;
    }

    @Override
    public ReportReturnVO report(BaseExpenditureImplementationDTO dto){
        List<Map<String, Object>> maps = new ArrayList<>();
        String orgId = TokenUtil.getTokenOrgId();
        List<String> orgIds = orgService.getAllChildIds(orgId);
        String year = dto.getYear();
        //执行数据
        List<BaseExpenditureImplementation> expenditureImplementations = list(new LambdaQueryWrapper<BaseExpenditureImplementation>().like(BaseExpenditureImplementation::getExecutionMonth, year)
                .in(BaseExpenditureImplementation::getFillingUnitId, orgIds).eq(BaseExpenditureImplementation::getStatus,FormStatusConstant.FINISH));
        Set<String> months = expenditureImplementations.stream().map(BaseExpenditureImplementation::getExecutionMonth).sorted().collect(Collectors.toCollection(LinkedHashSet::new));
        //预算数据
        List<AppraisalIndex> indexList = appraisalIndexService.listByTableCodeAndYear("005",year);
        List<String> codeLists = indexList.stream().map(AppraisalIndex::getCompleteCode).filter(m -> Optional.ofNullable(m).isPresent()).collect(Collectors.toList());
        List<FinanceIndicators> indicators = indicatorsMapper.selectList(new LambdaQueryWrapper<FinanceIndicators>().in(FinanceIndicators::getCode, codeLists));
        if (CollectionUtil.isNotEmpty(indicators)) {
            List<IndicatorsValue> indicatorsValues = indicatorsValueMapper.selectList(new LambdaQueryWrapper<IndicatorsValue>().in(IndicatorsValue::getOrgId,orgIds)
                    .eq(IndicatorsValue::getFyear, year).eq(IndicatorsValue::getFmonth, "00")
                    .in(IndicatorsValue::getIndicatorsId, indicators.stream().map(FinanceIndicators::getId).collect(Collectors.toList())));
            if (CollectionUtil.isNotEmpty(expenditureImplementations)){
                Set<String> fillOrgIds = expenditureImplementations.stream().map(BaseExpenditureImplementation::getFillingUnitId).collect(Collectors.toSet());
                List<Org> orgList = orgService.listByIds(fillOrgIds).stream().sorted(Comparator.comparing(Org::getOrderNum)).collect(Collectors.toList());
                for (Org org:orgList){
                    Map<String, Object> map = new HashMap<>();
                    map.put("orgName",org.getName());
                    //筛选预算
                    List<IndicatorsValue> values = indicatorsValues.stream().filter(m -> org.getId().equals(m.getOrgId())).collect(Collectors.toList());
                    BaseExpenditureImplementationVO expenditureImplementationVO = new BaseExpenditureImplementationVO();
                    getValue(values,indicators,expenditureImplementationVO);
                    //累计执行数
                    BigDecimal totalFee = BigDecimal.ZERO;
                    for (String month:months){
                        Optional<BaseExpenditureImplementation> first = expenditureImplementations.stream().filter(m -> month.equals(m.getExecutionMonth()) && org.getId().equals(m.getFillingUnitId())).findFirst();
                        if (first.isPresent()){
                            BaseExpenditureImplementation implementation = first.get();
                            totalFee = totalFee.add(implementation.getTotalFee());
                            setMapValue(implementation,expenditureImplementationVO,map,month);
                        }
                    }
                    BigDecimal totalBudge = expenditureImplementationVO.getTotalBudge();
                    map.put("total_Budge", totalBudge);
                    if (Optional.ofNullable(totalFee).isPresent() && Optional.ofNullable(totalBudge).isPresent()
                            && totalBudge.compareTo(BigDecimal.ZERO)>0){
                        BigDecimal divide = totalFee.multiply(new BigDecimal("100")).divide(totalBudge, 3, RoundingMode.HALF_UP);
                        map.put("total_Divide", divide);
                    }
                    maps.add(map);
                }
            }
        }
        //构成报表
        ReportVO reportVO = new ReportVO();
        List<HeaderVO> totalHeaders = new ArrayList<>();
        totalHeaders.add(HeaderVO.builder().key("total_Budge").title("年度预算总数").build());
        totalHeaders.add(HeaderVO.builder().key("total_Divide").title("累计执行进度").build());

        reportVO
                .addHeader(HeaderVO.builder().key("orgName").title("集团名称").build())
                .addHeader(HeaderVO.builder().title("合计").children(totalHeaders).build());
        if (CollectionUtil.isNotEmpty(months)){
            List<HeaderVO> monthHeader = new ArrayList<>();
            for (String month:months){
                List<HeaderVO> vehicleHeader = new ArrayList<>();
                vehicleHeader.add(HeaderVO.builder().key(month +"_" + "vehicleBudge").title("预算数").build());
                vehicleHeader.add(HeaderVO.builder().key(month +"_" + "vehicleFee").title("累计执行数").build());
                vehicleHeader.add(HeaderVO.builder().key(month +"_" + "vehicleDivide").title("累计执行率").build());

                List<HeaderVO> communicationHeader = new ArrayList<>();
                communicationHeader.add(HeaderVO.builder().key(month +"_" + "communicationBudge").title("预算数").build());
                communicationHeader.add(HeaderVO.builder().key(month +"_" + "communicationFee").title("累计执行数").build());
                communicationHeader.add(HeaderVO.builder().key(month +"_" + "communicationDivide").title("累计执行率").build());

                List<HeaderVO> entertainHeader = new ArrayList<>();
                entertainHeader.add(HeaderVO.builder().key(month +"_" + "entertainBudge").title("预算数").build());
                entertainHeader.add(HeaderVO.builder().key(month +"_" + "entertainFee").title("累计执行数").build());
                entertainHeader.add(HeaderVO.builder().key(month +"_" + "entertainDivide").title("累计执行率").build());

                List<HeaderVO> outsideHeader = new ArrayList<>();
                outsideHeader.add(HeaderVO.builder().key(month +"_" + "outsideBudge").title("预算数").build());
                outsideHeader.add(HeaderVO.builder().key(month +"_" + "outsideFee").title("累计执行数").build());
                outsideHeader.add(HeaderVO.builder().key(month +"_" + "outsideDivide").title("累计执行率").build());

                List<HeaderVO> tripHeader = new ArrayList<>();
                tripHeader.add(HeaderVO.builder().key(month +"_" + "tripBudge").title("预算数").build());
                tripHeader.add(HeaderVO.builder().key(month +"_" + "tripFee").title("累计执行数").build());
                tripHeader.add(HeaderVO.builder().key(month +"_" + "tripDivide").title("累计执行率").build());

                List<HeaderVO> valueHeader = new ArrayList<>();
                valueHeader.add(HeaderVO.builder().title("经营用车配备及使用费").child(vehicleHeader).build());
                valueHeader.add(HeaderVO.builder().title("通讯费").child(communicationHeader).build());
                valueHeader.add(HeaderVO.builder().title("业务招待费").child(entertainHeader).build());
                valueHeader.add(HeaderVO.builder().title("国（境）外考察培训费").child(outsideHeader).build());
                valueHeader.add(HeaderVO.builder().title("差旅费（含会议费）").child(tripHeader).build());

                reportVO.addHeader(HeaderVO.builder().title(month.split("-")[1] + "月").children(valueHeader).build());
            }
        }
        reportVO.setData(maps);
        ReportReturnVO reportReturnVO = new ReportReturnVO();
        reportReturnVO.setGrids(reportVO);
        return reportReturnVO;
    }

    @Override
    public List<ExpenditureOrgVO> getDataSummary(String year,String orgId){
        List<ExpenditureOrgVO> expenditureOrgVOS = new ArrayList<>();
        //父类Id
        Set<String> parentIds = orgService.list().stream().map(Org::getParentId).collect(Collectors.toSet());

        List<Org> orgList = orgService.getAllChild(orgId);
        orgList.remove(orgService.getById(orgId));
        if (CollectionUtil.isNotEmpty(orgList)){
            //执行数据
            List<BaseExpenditureImplementation> expenditureImplementations = list(new LambdaQueryWrapper<BaseExpenditureImplementation>().like(BaseExpenditureImplementation::getExecutionMonth, year)
                    .in(BaseExpenditureImplementation::getFillingUnitId, orgList.stream().map(Org::getId).collect(Collectors.toList())));
            if (CollectionUtil.isNotEmpty(expenditureImplementations)){
                for (BaseExpenditureImplementation implementation:expenditureImplementations){
                    String childOrgId = implementation.getFillingUnitId();
                    ExpenditureOrgVO expenditureOrgVO = ExpenditureOrgVO.builder().orgId(childOrgId).status(implementation.getStatus()).build();
                    orgList.stream().filter(org -> childOrgId.equals(org.getId())).findFirst().ifPresent(m -> expenditureOrgVO.setOrgName(m.getName()));
                    if (parentIds.contains(childOrgId)){
                        expenditureOrgVO.setBaseType(1);
                    }else {
                        expenditureOrgVO.setBaseType(2);
                    }
                    expenditureOrgVOS.add(expenditureOrgVO);
                }
            }
        }
        return expenditureOrgVOS;
    }

    /**
     * @Description: //TODO 放置map值
     * @Author: Take-off
     * @Date: 11:11 AM 2023/3/14
     * @Param: [implementation, expenditureImplementationVO, map]
     * @return: void
     **/
    private void setMapValue(BaseExpenditureImplementation implementation,BaseExpenditureImplementationVO expenditureImplementationVO,Map<String, Object> map,String month){
        BigDecimal vehicleFee = implementation.getVehicleFee();
        BigDecimal vehicleBudge = expenditureImplementationVO.getVehicleBudge();
        map.put(month +"_" + "vehicleFee", vehicleFee);
        map.put(month +"_" + "vehicleBudge", vehicleBudge);
        if (Optional.ofNullable(vehicleFee).isPresent() && Optional.ofNullable(vehicleBudge).isPresent()
                && vehicleBudge.compareTo(BigDecimal.ZERO)>0){
            BigDecimal divide = vehicleFee.multiply(new BigDecimal("100")).divide(vehicleBudge, 3, RoundingMode.HALF_UP);
            map.put(month +"_" + "vehicleDivide", divide);
        }

        BigDecimal communicationFee = implementation.getCommunicationFee();
        BigDecimal communicationBudge = expenditureImplementationVO.getCommunicationBudge();
        map.put(month +"_" + "communicationFee", communicationFee);
        map.put(month +"_" + "communicationBudge", communicationBudge);
        if (Optional.ofNullable(communicationFee).isPresent() && Optional.ofNullable(communicationBudge).isPresent()
                && communicationBudge.compareTo(BigDecimal.ZERO)>0){
            BigDecimal divide = communicationFee.multiply(new BigDecimal("100")).divide(communicationBudge, 3, RoundingMode.HALF_UP);
            map.put(month +"_" + "communicationDivide", divide);
        }

        BigDecimal entertainFee = implementation.getEntertainFee();
        BigDecimal entertainBudge = expenditureImplementationVO.getEntertainBudge();
        map.put(month +"_" + "entertainFee", entertainFee);
        map.put(month +"_" + "entertainBudge", entertainBudge);
        if (Optional.ofNullable(entertainFee).isPresent() && Optional.ofNullable(entertainBudge).isPresent()
                && entertainBudge.compareTo(BigDecimal.ZERO)>0){
            BigDecimal divide = entertainFee.multiply(new BigDecimal("100")).divide(entertainBudge, 3, RoundingMode.HALF_UP);
            map.put(month +"_" + "entertainDivide", divide);
        }

        BigDecimal outsideFee = implementation.getOutsideFee();
        BigDecimal outsideBudge = expenditureImplementationVO.getOutsideBudge();
        map.put(month +"_" + "outsideFee", outsideFee);
        map.put(month +"_" + "outsideBudge", outsideBudge);
        if (Optional.ofNullable(outsideFee).isPresent() && Optional.ofNullable(outsideBudge).isPresent()
                && outsideBudge.compareTo(BigDecimal.ZERO)>0){
            BigDecimal divide = outsideFee.multiply(new BigDecimal("100")).divide(outsideBudge, 3, RoundingMode.HALF_UP);
            map.put(month +"_" + "outsideDivide", divide);
        }

        BigDecimal tripFee = implementation.getTripFee();
        BigDecimal tripBudge = expenditureImplementationVO.getTripBudge();
        map.put(month +"_" + "tripFee", outsideFee);
        map.put(month +"_" + "tripBudge", tripBudge);
        if (Optional.ofNullable(tripFee).isPresent() && Optional.ofNullable(tripBudge).isPresent()
                && tripBudge.compareTo(BigDecimal.ZERO)>0){
            BigDecimal divide = tripFee.multiply(new BigDecimal("100")).divide(tripBudge, 3, RoundingMode.HALF_UP);
            map.put(month +"_" + "tripDivide", divide);
        }
    }

    @Override
    public ListResult<BaseExpenditureImplementationVO> treeList(Query query) {
        List<BaseExpenditureImplementationVO> results = new ArrayList<>();

        //父类Id
        Set<String> parentIds = orgService.list().stream().map(Org::getParentId).collect(Collectors.toSet());

        String orgId = TokenUtil.getTokenOrgId();
        List<Org> orgList = orgService.getAllChild(orgId);
        if (CollectionUtil.isEmpty(orgList)){
            throw new MyRuntimeException(new ObjResult("获取单位信息失败！"));
        }
        List<OrgVO> orgVOList = ForestNodeMerger.merge(orgWrapper.entityToVO(orgList));

        List<String> orgIds = orgList.stream().map(Org::getId).collect(Collectors.toList());
        ListResult<BaseExpenditureImplementationVO> listResult = new ListResult<>(CommonCode.SUCCESS);
        IPage<String> fillingYearPage = getBaseMapper().getFillingYearPage(Condition.getPage(query), orgIds, query.getKeyword());
        if (CollectionUtil.isEmpty(fillingYearPage.getRecords())){
            return listResult;
        }
        List<BaseExpenditureImplementationVO> expenditureImplementationVOS = implementationWrapper.entityToVO(list(Wrappers.<BaseExpenditureImplementation>lambdaQuery()
                .in(BaseExpenditureImplementation::getExecutionMonth, fillingYearPage.getRecords())));
        if (CollectionUtil.isNotEmpty(expenditureImplementationVOS)){
            Map<String, List<BaseExpenditureImplementationVO>> fillingMonthMap = expenditureImplementationVOS.stream().collect(Collectors.groupingBy(BaseExpenditureImplementationVO::getExecutionMonth));
            fillingMonthMap.forEach((k, dataList) -> {
                Map<String, BaseExpenditureImplementationVO> orgIdMap = dataList.stream().collect(Collectors.toMap(BaseExpenditureImplementationVO::getFillingUnitId, vo -> vo));
                results.addAll(orgVOToIndicatorsVO(k, orgVOList, orgIdMap));
            });
            listResult.setTotal(Long.valueOf(fillingYearPage.getTotal()).intValue());
            listResult.setList(results);
        }
        return listResult;
    }

    @Override
    public BaseExpenditureImplementationVO addSumValue(List<String> orgIds, String executionMonth){
        BaseExpenditureImplementationVO expenditureImplementationVO = new BaseExpenditureImplementationVO();
        if (CollectionUtil.isNotEmpty(orgIds)){
            //获取他们的当月执行数
            List<BaseExpenditureImplementation> implementations = list(new LambdaQueryWrapper<BaseExpenditureImplementation>().in(BaseExpenditureImplementation::getFillingUnitId, orgIds).eq(BaseExpenditureImplementation::getExecutionMonth, executionMonth));
            if (CollectionUtil.isNotEmpty(implementations)){
                expenditureImplementationVO.setVehicleFeeSum(
                        implementations.stream().map(BaseExpenditureImplementation::getVehicleFeeSum).filter(m -> Optional.ofNullable(m).isPresent()).reduce(BigDecimal.ZERO,BigDecimal::add)
                );
                expenditureImplementationVO.setCommunicationFeeSum(
                        implementations.stream().map(BaseExpenditureImplementation::getCommunicationFeeSum).filter(m -> Optional.ofNullable(m).isPresent()).reduce(BigDecimal.ZERO,BigDecimal::add)
                );
                expenditureImplementationVO.setEntertainFeeSum(
                        implementations.stream().map(BaseExpenditureImplementation::getEntertainFeeSum).filter(m -> Optional.ofNullable(m).isPresent()).reduce(BigDecimal.ZERO,BigDecimal::add)
                );
                expenditureImplementationVO.setOutsideFeeSum(
                        implementations.stream().map(BaseExpenditureImplementation::getOutsideFeeSum).filter(m -> Optional.ofNullable(m).isPresent()).reduce(BigDecimal.ZERO,BigDecimal::add)
                );
                expenditureImplementationVO.setTripFeeSum(
                        implementations.stream().map(BaseExpenditureImplementation::getTripFeeSum).filter(m -> Optional.ofNullable(m).isPresent()).reduce(BigDecimal.ZERO,BigDecimal::add)
                );
                expenditureImplementationVO.setTotalFeeSum(
                        implementations.stream().map(BaseExpenditureImplementation::getTotalFeeSum).filter(m -> Optional.ofNullable(m).isPresent()).reduce(BigDecimal.ZERO,BigDecimal::add)
                );
            }else {
                expenditureImplementationVO.setVehicleFeeSum(BigDecimal.ZERO);
                expenditureImplementationVO.setCommunicationFeeSum(BigDecimal.ZERO);
                expenditureImplementationVO.setEntertainFeeSum(BigDecimal.ZERO);
                expenditureImplementationVO.setOutsideFeeSum(BigDecimal.ZERO);
                expenditureImplementationVO.setTripFeeSum(BigDecimal.ZERO);
                expenditureImplementationVO.setTotalFeeSum(BigDecimal.ZERO);
            }
        }else {
            expenditureImplementationVO.setVehicleFeeSum(BigDecimal.ZERO);
            expenditureImplementationVO.setCommunicationFeeSum(BigDecimal.ZERO);
            expenditureImplementationVO.setEntertainFeeSum(BigDecimal.ZERO);
            expenditureImplementationVO.setOutsideFeeSum(BigDecimal.ZERO);
            expenditureImplementationVO.setTripFeeSum(BigDecimal.ZERO);
            expenditureImplementationVO.setTotalFeeSum(BigDecimal.ZERO);
        }
        //获取自己的本年执行数
        List<BaseExpenditureImplementation> ownImplementtations = list(new LambdaQueryWrapper<BaseExpenditureImplementation>()
                .eq(BaseExpenditureImplementation::getFillingUnitId, TokenUtil.getTokenOrgId())
                .like(BaseExpenditureImplementation::getExecutionMonth, executionMonth.split("-")[0])
                .ne(BaseExpenditureImplementation::getExecutionMonth,executionMonth)
        );

        if (CollectionUtil.isNotEmpty(ownImplementtations)){
            ownImplementtations.stream().sorted(Comparator.comparing(BaseExpenditureImplementation::getExecutionMonth).reversed()).findFirst().ifPresent(own -> {
                expenditureImplementationVO.setVehicleFeeSum(expenditureImplementationVO.getVehicleFeeSum().add(own.getVehicleFeeSum()));
                expenditureImplementationVO.setCommunicationFeeSum(expenditureImplementationVO.getCommunicationFeeSum().add(own.getCommunicationFeeSum()));
                expenditureImplementationVO.setEntertainFeeSum(expenditureImplementationVO.getEntertainFeeSum().add(own.getEntertainFeeSum()));
                expenditureImplementationVO.setOutsideFeeSum(expenditureImplementationVO.getOutsideFeeSum().add(own.getOutsideFeeSum()));
                expenditureImplementationVO.setTripFeeSum(expenditureImplementationVO.getTripFeeSum().add(own.getTripFeeSum()));
                expenditureImplementationVO.setTotalFeeSum(expenditureImplementationVO.getTotalFeeSum().add(own.getTotalFeeSum()));
            });
        }
        return expenditureImplementationVO;
    }

    private List<BaseExpenditureImplementationVO> orgVOToIndicatorsVO(String executionMonth, List<OrgVO> orgVOList, Map<String, BaseExpenditureImplementationVO> orgIdMap){
        List<String> parentIds = orgVOList.stream().map(OrgVO::getParentId).collect(Collectors.toList());
        List<BaseExpenditureImplementationVO> childList = new ArrayList<>();
        for (OrgVO orgVO : orgVOList){
            String orgId = orgVO.getId();
            BaseExpenditureImplementationVO expenditureImplementationVO = orgIdMap.get(orgId);

            if (expenditureImplementationVO == null){
                expenditureImplementationVO = new BaseExpenditureImplementationVO();
                expenditureImplementationVO.setFillingUnitId(orgId);
                expenditureImplementationVO.setStatus(FormStatusConstant.NOFILLING);
                expenditureImplementationVO.setExecutionMonth(executionMonth);
            }
            expenditureImplementationVO.setFillingUnitName(orgVO.getName());
            childList.add(expenditureImplementationVO);
            if (CollectionUtil.isNotEmpty(orgVO.getChildren())){
                expenditureImplementationVO.setChildren(orgVOToIndicatorsVO(executionMonth, orgVO.getChildren(), orgIdMap));
            }
            if (parentIds.contains(orgId)){
                expenditureImplementationVO.setBaseType(1);
            }else {
                expenditureImplementationVO.setBaseType(2);
            }
        }
        return childList;
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public BaseExpenditureImplementationVO initialization(BaseExpenditureImplementationVO expenditureImplementationVO) {
        if (StringUtil.isBlank(expenditureImplementationVO.getExecutionMonth())){
            throw new MyRuntimeException(new ObjResult("执行年月为空！"));
        }
        String tokenOrgId = TokenUtil.getTokenOrgId();
        BaseExpenditureImplementation baseExpenditureImplementation = getOne(Wrappers.<BaseExpenditureImplementation>lambdaQuery()
                .eq(BaseExpenditureImplementation::getExecutionMonth, expenditureImplementationVO.getExecutionMonth())
                .eq(BaseExpenditureImplementation::getFillingUnitId, tokenOrgId));
        if (baseExpenditureImplementation != null){
            throw new MyRuntimeException(new ObjResult("该年月已填报！"));
        }
        BaseExpenditureImplementation initBase = new BaseExpenditureImplementation();
        initBase.setExecutionMonth(expenditureImplementationVO.getExecutionMonth());
        initBase.setFillingUnitId(tokenOrgId);
        saveOrUpdate(initBase);
        return implementationWrapper.entityToVO(initBase);
    }
}
